////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "Test_IntersectionGameImpl.hpp"

#include <iostream>
#include <sstream>

#include <SFML/Graphics.hpp>

#include <SmegCore/Math/BoundingVolumes/BoundingVolumes.h>

#include <SmegTools/Debug/DebugNew.hpp>

////////////////////////////////////////////////////////////
/// Constructor
////////////////////////////////////////////////////////////
Test_IntersectionGameImpl::Test_IntersectionGameImpl() :
    DefaultGameImpl(),
    m_bPause( false ),
    m_bOverlapTest( true ),
    m_bContainmentTest( true ),
    m_pFont( NULL ),
    m_pInfo( NULL ),
    m_eVolumeType( eAABB ),
    m_pTestVolume( NULL )
{
}

////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////
Test_IntersectionGameImpl::~Test_IntersectionGameImpl()
{
}

////////////////////////////////////////////////////////////
/// Init the game
////////////////////////////////////////////////////////////
void Test_IntersectionGameImpl::Init( sf::RenderWindow* _pRenderWindow ) {
    DefaultGameImpl::Init( _pRenderWindow );
    m_pRenderWindow->setMouseCursorVisible( false );

    // Info
    m_pFont = new sf::Font();
    if ( m_pFont->loadFromFile( "data/fonts/COUR.ttf" ) ) {
        m_pInfo = new sf::Text("FPS : 0\n",
                                *m_pFont,
                                12);
        m_pInfo->setColor( sf::Color::White );
    }

    ChangeVolume( m_eVolumeType );
    
    // AABB1
    smeg::math::BoundingBox* pAABB1 = new smeg::math::BoundingBox( sf::Vector2f( 200.0f, 100.0f ), sf::Vector2f( 300.0f, 150.0f ) );
    m_Volumes.push_back( pAABB1 );

    // AABB2
    smeg::math::BoundingBox* pAABB2 = new smeg::math::BoundingBox( sf::Vector2f( 500.0f, 100.0f ), sf::Vector2f( 75.0f, 25.0f ) );
    m_Volumes.push_back( pAABB2 );

    // OBB 1
    smeg::math::BoundingBox* pOBB1 = new smeg::math::BoundingBox( sf::Vector2f( 600.0f, 250.0f ), sf::Vector2f( 50.0f, 75.0f ), 65.0f );
    m_Volumes.push_back( pOBB1 );

    // OBB 2
    smeg::math::BoundingBox* pOBB2 = new smeg::math::BoundingBox( sf::Vector2f( 350.0f, 500.0f ), sf::Vector2f( 400.0f, 300.0f ), -25.0f );
    m_Volumes.push_back( pOBB2 );

    // Circle1
    smeg::math::Circle* pCircle1 = new smeg::math::Circle( sf::Vector2f( 700.0f, 400.0f ), 80.0f );
    m_Volumes.push_back( pCircle1 );

    // Circle2
    smeg::math::Circle* pCircle2 = new smeg::math::Circle( sf::Vector2f( 700.0f, 650.0f ), 250.0f );
    m_Volumes.push_back( pCircle2 );

    // Line1
    smeg::math::Line* pLine1 = new smeg::math::Line( sf::Vector2f( 800.0f, 75.0f ), sf::Vector2f( 940.0f, 650.0f ) );
    m_Volumes.push_back( pLine1 );

    // Line2
    smeg::math::Line* pLine2 = new smeg::math::Line( sf::Vector2f( 900.0f, 75.0f ), sf::Vector2f( 850.0f, 100.0f ) );
    m_Volumes.push_back( pLine2 );
}

////////////////////////////////////////////////////////////
/// DeInit the game
////////////////////////////////////////////////////////////
void Test_IntersectionGameImpl::DeInit() {
    delete m_pFont;
    m_pFont = NULL;
    delete m_pInfo;
    m_pInfo = NULL;

    delete m_pTestVolume;
    m_pTestVolume = NULL;

    for ( unsigned i = 0; i < m_Volumes.size(); ++i ) {
        delete m_Volumes[i];
    }
    m_Volumes.clear();

    DefaultGameImpl::DeInit();
}

////////////////////////////////////////////////////////////
/// Manage an incoming event
////////////////////////////////////////////////////////////
void Test_IntersectionGameImpl::ManageEvent( const sf::Event& _Event ) {
    DefaultGameImpl::ManageEvent( _Event );

    switch ( _Event.type ) {
        case sf::Event::KeyPressed: {
            switch( _Event.key.code ) {
                // Change volume
                case sf::Keyboard::Up:
                    ChangeVolume( m_eVolumeType + 1 );
                    break;
                case sf::Keyboard::Down:
                    ChangeVolume( m_eVolumeType - 1 );
                    break;

                case sf::Keyboard::F1:
                    m_bPause = !m_bPause;
                    break;
                case sf::Keyboard::F2:
                    m_bOverlapTest = !m_bOverlapTest;
                    break;
                case sf::Keyboard::F3:
                    m_bContainmentTest = !m_bContainmentTest;
                    break;
            }
        }
    }
}

////////////////////////////////////////////////////////////
/// Call all the Update in the other systems
////////////////////////////////////////////////////////////
void Test_IntersectionGameImpl::Update( float _fDeltaTime  ) {
    DefaultGameImpl::Update( _fDeltaTime );

    if ( !m_bPause ) {
        m_pTestVolume->SetCenter( (float)sf::Mouse::getPosition( *m_pRenderWindow ).x, (float)sf::Mouse::getPosition( *m_pRenderWindow ).y );
    }
    
    std::stringstream infoStr;
    infoStr << "Pause (F1) : " << (m_bPause ? "ON" : "OFF") << std::endl;
    infoStr << "Pos  : " << sf::Mouse::getPosition( *m_pRenderWindow ).x << "," << sf::Mouse::getPosition( *m_pRenderWindow ).y << std::endl;
    infoStr << "Overlap Test (F2) : " << (m_bOverlapTest ? "ON" : "OFF") << std::endl;
    infoStr << "Containment Test (F3) : " << (m_bContainmentTest ? "ON" : "OFF") << std::endl;

    m_pInfo->setString( infoStr.str() );
}

////////////////////////////////////////////////////////////
/// Call all the Render in the other systems
////////////////////////////////////////////////////////////
void Test_IntersectionGameImpl::Render() {
    DefaultGameImpl::Render();

    bool bContain = false,
        bIsContained = false,
        bOverlap = false,
        bLineIntersect = false;
    sf::Vector2f LineIntersectionPoint;

    for ( unsigned i = 0; i < m_Volumes.size(); ++i ) {
        if ( m_bContainmentTest && m_Volumes[i]->ContainsUnknownBBPtr( m_pTestVolume ) ) {
            m_Volumes[i]->DebugRender( m_pRenderWindow, sf::Color::Blue );
            bIsContained = true;
        } else if ( m_bContainmentTest &&m_pTestVolume->ContainsUnknownBBPtr( m_Volumes[i] ) ) {
            m_Volumes[i]->DebugRender( m_pRenderWindow, sf::Color::Green );
            bContain = true;
        } else if ( m_bOverlapTest && m_Volumes[i]->OverlapsUnknownBBPtr( m_pTestVolume ) ) {
            m_Volumes[i]->DebugRender( m_pRenderWindow, sf::Color::Red );
            bOverlap = true;

            if ( m_Volumes[i]->GetType() == smeg::math::BoundingVolume::eLine && m_pTestVolume->GetType() == smeg::math::BoundingVolume::eLine ) {
                static_cast< smeg::math::Line* >( m_Volumes[i] )->Intersects( *static_cast< smeg::math::Line* >( m_pTestVolume ), LineIntersectionPoint );
                bLineIntersect = true;
            }
        } else {
            m_Volumes[i]->DebugRender( m_pRenderWindow );
        }
    }

    if ( bOverlap ) {
        m_pTestVolume->DebugRender( m_pRenderWindow, sf::Color::Red );
        if ( bLineIntersect ) {
            sf::CircleShape Circle( 3.0f );
            Circle.setOrigin( 3.0f, 3.0f );
            Circle.setFillColor( sf::Color::Yellow );
            Circle.setPosition( LineIntersectionPoint );
            m_pRenderWindow->draw( Circle );
        }
    } else if ( bIsContained ) {
        m_pTestVolume->DebugRender( m_pRenderWindow, sf::Color::Green );
    } else if ( bContain ) {
        m_pTestVolume->DebugRender( m_pRenderWindow, sf::Color::Blue );
    } else {
        m_pTestVolume->DebugRender( m_pRenderWindow );
    }

    // Show info
    m_pRenderWindow->draw( *m_pInfo );
}

void Test_IntersectionGameImpl::ChangeVolume( int _iNewVolume ) {
    delete m_pTestVolume;
    m_pTestVolume = NULL;

    if ( _iNewVolume < 0 ) {
        m_eVolumeType = (eVolumeType)(eMAX_VOLUME - 1);
    } else if ( _iNewVolume >= eMAX_VOLUME ) {
        m_eVolumeType = (eVolumeType)0;
    } else {
        m_eVolumeType = (eVolumeType)_iNewVolume;
    }

    switch( m_eVolumeType ) {
    case eAABB:
        m_pTestVolume = new smeg::math::BoundingBox();
        static_cast<smeg::math::BoundingBox*>(m_pTestVolume)->Setup( sf::Vector2f( m_pRenderWindow->getSize().x * 0.5f, m_pRenderWindow->getSize().y * 0.5f ), sf::Vector2f( 150.0f, 100.0f ) );
        break;
    case eCircle:
        m_pTestVolume = new smeg::math::Circle();
        m_pTestVolume->Setup( sf::Vector2f( m_pRenderWindow->getSize().x * 0.5f, m_pRenderWindow->getSize().y * 0.5f ), sf::Vector2f( 100.0f, 100.0f ) );
        break;
    case eLine:
        m_pTestVolume = new smeg::math::Line();
        m_pTestVolume->Setup( sf::Vector2f( -20.f, -25.f ), sf::Vector2f( 40.0f, 10.0f ) );
        m_pTestVolume->SetCenter( m_pRenderWindow->getSize().x * 0.5f, m_pRenderWindow->getSize().y * 0.5f );
        break;
    case eOBB:
        m_pTestVolume = new smeg::math::BoundingBox();
        static_cast<smeg::math::BoundingBox*>(m_pTestVolume)->Setup( sf::Vector2f( m_pRenderWindow->getSize().x * 0.5f, m_pRenderWindow->getSize().y * 0.5f ), sf::Vector2f( 150.0f, 100.0f ), 20.0f );
        break;
    }
}
